package com.dc.datacollect.components.upload;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 文件服务器响应控制器
 *
 * @author zhuangjie
 * @date 2023/05/13
 */
@RestController
//@Api(tags = "文件读取服务")
public class FileResponseServerController  {
    /**
     * 网站统一前缀（默认就是""空字符串）
     */
    @Value("${server.servlet.context-path:}")
    private String appPrefix;

    @Value("${component-service.upload.store-vest:}")
    private String storeVest;

    @Value("${component-service.upload.request-vest:}")
    private String requestVest;
    private static Map<String, String> typeSuffixMap = new HashMap<>(16);


    static {
        // 图片类型
        typeSuffixMap.put(".jpg", "image/jpeg");
        typeSuffixMap.put(".gif", "image/gif");
        typeSuffixMap.put(".png", "image/png");
        // 音频类型
        typeSuffixMap.put(".mp3", "audio/mpeg");
        // 视频类型
        typeSuffixMap.put(".mp4", "video/mp4");
        typeSuffixMap.put(".avi", "video/x-msvideo");
        // 其它类型都以二进制流的方式 application/octet-stream
    }

    @Resource
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    /**
     * 用于动态注册请求
     * 项目启动后，会自动执行被@PostConstruct修饰的方法
     */
    @PostConstruct
    public void registryUploadRequestMapping() {
        System.out.println("执行了" + requestMappingHandlerMapping);
        // 指定URL
        RequestMappingInfo requestMappingInfo = RequestMappingInfo.paths(appPrefix+requestVest + "/**")
                .methods(RequestMethod.GET)
                .build();
        try {
            // 指定URL对应的Method
            Method targetMethod = this.getClass().getDeclaredMethod("responseUploadResource",String.class, HttpServletRequest.class, HttpServletResponse.class);
            // 注册 RequestMapping
            requestMappingHandlerMapping.registerMapping(requestMappingInfo, this, targetMethod);
        } catch (NoSuchMethodException e) {
            System.out.println("[ERROR] 注册UploadRequestMapping失败，文件请求功能将无法使用！");
            e.printStackTrace();
        }
    }

    /**
     * 手动注册的请求handle处理器：响应上传资源
     *
     * @param req 要求事情
     * @param res res
     */
//    @ApiOperation("文件响应")
    public void responseUploadResource(@RequestParam(value = "filename",required = false) String filename,  HttpServletRequest req, HttpServletResponse res) throws IOException {

        // 得到存放路径("/dj/upload")后面的路径比如  http://localhost:8089/dj/upload/2022-12-1/java.jpg childPath就是 /2022-12-1/java.jpg
        String childPath = req.getServletPath().split(requestVest)[1];
        // 拼成保存在本地的存储路径，如 /dj/upload/2022-12-1/java.jpg （如果winDriveLetter是“C:”,那Win下就是:   C:/dj/upload/2022-12-1/java.jpg）
        String storePath = storeVest + childPath;
        File file = new File(storePath);

        // 设置响应头
        String suffix = storePath.substring(storePath.lastIndexOf(".") + 1).toLowerCase();
        if (filename != null && ! filename.isEmpty()) {
            res.setContentType("application/octet-stream");
            // 对文件名进行编码，以支持响应为中文文件名下载
            String encodedFileName = Base64.getEncoder().encodeToString((filename+"."+suffix).getBytes(StandardCharsets.UTF_8));
            encodedFileName = "=?UTF-8?B?" + encodedFileName + "?=";
            res.setHeader("Content-Disposition", "attachment;filename=\""+encodedFileName+"\"");
        }
        res.setContentType(fileSuffixSwitchResponseType(suffix));

        // 读取文件并输出
        try (FileInputStream fis = new FileInputStream(file);
             OutputStream os = res.getOutputStream()) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
        } catch (FileNotFoundException e) {
            res.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }

    /**
     * 根据文件后缀返回文件类型
     */
    private static String fileSuffixSwitchResponseType(String fileSuffix) {
        fileSuffix = fileSuffix.trim();
        // 对照表进行获取
        Set<Map.Entry<String, String>> entries = typeSuffixMap.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            String suffix = entry.getKey();
            String type = entry.getValue();
            if (suffix.equals(fileSuffix)) {
                return type;
            }
        }
        // 到这里是没有找到的,统一返回“二进制流”
        return "application/octet-stream";
    }

    public File urlToFile(String url) {
        // 得到存放路径("/dj/upload")后面的路径比如  http://localhost:8089/dj/upload/2022-12-1/java.jpg childPath就是 /2022-12-1/java.jpg
        String childPath = url.split(requestVest)[1];
        // 拼成保存在本地的存储路径，如 /dj/upload/2022-12-1/java.jpg （如果winDriveLetter是“C:”,那Win下就是:   C:/dj/upload/2022-12-1/java.jpg）
        String storePath = storeVest + childPath;
        return new File(storePath);
    }

    public void fileWrapProcess(List<UploadFileWrap> uploadFileWrapList) {
        uploadFileWrapList.stream().forEach(uploadFileWrap -> {
            String url = uploadFileWrap.getUrl();
            uploadFileWrap.setFile(urlToFile(url));
        });
    }
}

